/**
 * 配置
 * */
package org.zmhhxl.sample3.oauth2.a.configure;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.web.cors.CorsConfigurationSource;
import org.zmhhxl.sample3.oauth2.a.mapper.CustomUserInfoMapper;

//授权服务器，同时是客户端(认证用户)
//安全过滤链
@Configuration(proxyBeanMethods = false)
//@EnableWebSecurity
@Slf4j
public class OAuth2SecurityFilterConfig{
   private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent";

   @Autowired
   private /*final*/ CorsConfigurationSource corsConfigurationSource  ;



   @Bean
   @Order(Ordered.HIGHEST_PRECEDENCE)   //越小越先
   public SecurityFilterChain authorizationServerSecurityFilterChain(
         HttpSecurity http) throws Exception {

      OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

//      http.headers(headers -> headers
//            .frameOptions(frameOptions -> frameOptions.sameOrigin()) //.disable()
////            .contentSecurityPolicy(contentSecurityPolicy -> contentSecurityPolicy
////                  .policyDirectives(
////                        "default-src 'self'; frame-ancestors 'self'; "   //frame-ancestors 'http://127.0.0.1:4200'
////                  )
////            )
//      );
  //          .contentSecurityPolicy("default-src 'self'; frame-ancestors 'http://127.0.0.1:4200")
 //           .frameOptions()
 //           .sameOrigin()  ;

      //@Order(Ordered.HIGHEST_PRECEDENCE+1) CsrfFilter
      //WebAsyncManagerIntegrationFilter  AnonymousAuthenticationFilter
      // UsernamePasswordAuthenticationFilter HeaderWriterFilter后
      //DisableEncodeUrlFilter  HeaderWriterFilter  AuthorizationServerContextFilter
      //http.addFilter(corsFilter);

      // 配置 CORS,指定不同的 CorsConfigurationSource
      http.cors(cors ->cors.configurationSource(corsConfigurationSource));  //.configurationSource(corsConfigurationSource);


// 采用自定义的 userInfoMapper来添加user信息,可以添加其他信息 todo 待完
//      Function<OidcUserInfoAuthenticationContext, OidcUserInfo> userInfoMapper = (context) -> {
//         OidcUserInfoAuthenticationToken authentication = context.getAuthentication();
//         JwtAuthenticationToken principal = (JwtAuthenticationToken) authentication.getPrincipal();
//
//         return new OidcUserInfo(principal.getToken().getClaims());
//      };

      http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            // 配置授权页面
            .authorizationEndpoint( authorizationEndpoint ->{
                     authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI);
               }
            )
            .oidc( // 支持OpenID Connect协议  Customizer.withDefaults()
                  // 配置 userInfoEndpoint todo 待完
                  oidc ->{
                     log.info("OAuth2安全配置 kkkkk 实现用户信息映射");    //启动时运行一次
                     oidc.userInfoEndpoint(userInfo ->
                           userInfo.userInfoMapper(new CustomUserInfoMapper())
//                                   .userInfoResponseHandler(userInfoResponseHandler)
//                                   ...共7个配置

                           )
                     ;

                     Customizer.withDefaults();

                  }
            );

      // 禁用 csrf 与 cors
    //  http.csrf(AbstractHttpConfigurer::disable);
      //http.cors(AbstractHttpConfigurer::disable);

      http
            .exceptionHandling(exceptions -> exceptions
//                  .defaultAuthenticationEntryPointFor(
//                        new LoginUrlAuthenticationEntryPoint("/login"), // CUSTOM_CONSENT_PAGE_URI "/oauth2/consent"
//                        new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
//                  )  //http://127.0.0.1:4200/should-login

                  .authenticationEntryPoint(
                        // 异常或拒绝时的登录页面
                        new LoginUrlAuthenticationEntryPoint("/login")  //不行 http://127.0.0.1:4200
                        )

                  .accessDeniedHandler((request, response, accessDeniedException) -> {
                     String msg =  "Access denied for request: "  + request.getRequestURI() + ". Method: " + request.getMethod() + ". Reason: " + accessDeniedException.getMessage();
                     log.info("拒绝访问 ccccc ======== /r"+msg);
                  })
                  //.accessDeniedPage("/login")   //  /error

            )
            //启用了Spring Security提供的OAuth2资源服务配置，用于保护OpenID Connect中/userinfo用户信息端点
            .oauth2ResourceServer(
                  //OAuth2ResourceServerConfigurer::jwt //已经弃用
                  (oauth2ResourceServer) ->{
                     oauth2ResourceServer.jwt(Customizer.withDefaults())
//                           .accessDeniedHandler()
//                           .authenticationEntryPoint()
                     ;
                     //oauth2ResourceServer.opaqueToken(Customizer.withDefaults()); //设置不透明.introspectionClientRegistrationId("introspection")
                  }
            )
      ;
      return http.build();
   }

//   @Bean
//   public OAuth2UserService<OidcUserInfoAuthenticationContext> oidcUserService(CustomUserInfoMapper customUserInfoMapper) {
//      OidcUserService oidcUserService = new OidcUserService();
//      oidcUserService.setOidcUserInfoService(new OidcUserInfoService() {
//         @Override
//         public OidcUser loadUser(OidcUserInfoAuthenticationContext context) {
//            return customUserInfoMapper.apply(context);
//         }
//      });
//      return oidcUserService;
//   }

}
